 #define _CRT_SECURE_NO_WARNINGS 1

// 双向链表,用于存储访问节点
struct Node {
    int _key, _value;
    Node* prev;
    Node* next;
    Node() : _key(0), _value(0), prev(nullptr), next(nullptr) {}
    Node(int key, int value)
        : _key(key), _value(value), prev(nullptr), next(nullptr) {}
};

class LRUCache {
private:
    unordered_map<int, Node*> cache;
    Node* _head;
    Node* _tail;
    int _size;
    int _capacity;

public:
    LRUCache(int capacity) : _capacity(capacity), _size(0) {
        // 构造函数使用伪头结点和尾节点
        _head = new Node();
        _tail = new Node();
        _head->next = _tail;
        _tail->prev = _head;
    }

    void addTohead(Node* node) {
        node->prev = _head;
        node->next = _head->next;
        _head->next->prev = node;
        _head->next = node;
    }

    void removeNode(Node* node) {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }

    Node* removeTail() {
        Node* node = _tail->prev;
        removeNode(node);
        return node;
    }

    void moveToHead(Node* node) {
        removeNode(node);
        addTohead(node);
    }

    int get(int key) {
        if (!cache.count(key)) {
            return -1;
        }
        // 如果对应的key值存在则直接通过哈希表访问，并移动到头部
        Node* node = cache[key];
        moveToHead(node);
        return node->_value;
    }

    void put(int key, int value) {
        if (!cache.count(key)) {
            // 如果key值不存在这个链表中，则创建一个新的节点
            Node* node = new Node(key, value);
            // 添加进哈希表
            cache[key] = node;
            // 添加进双向链表，因为是新建节点，直接添加到头部
            addTohead(node);
            ++_size;
            if (_size > _capacity) {
                // 如果这时候超出容量，则直接移除尾部节点
                Node* remove = removeTail();
                // 删除对应哈希表的值
                cache.erase(remove->_key);

                delete remove;
                --_size;
            }
        }
        else {
            // 如果key值存在，则直接通过哈希表定位，再修改对应value，并移到头部
            Node* node = cache[key];
            node->_value = value;
            moveToHead(node);
        }
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */